﻿using LD.Common;
using LD.PLC;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

namespace LD
{
    public class ScrewManger
    {
        private Dictionary<string, TaskEx> tasks;
        private static ScrewManger instance;
        private static object locker = new object();
        private static object dbLocker = new object();
        private ScrewManger() { }
        public static ScrewManger Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (locker)
                    {
                        if (instance == null)
                            instance = new ScrewManger();
                    }
                }
                return instance;
            }
        }
        public Dictionary<string, ScrewHelper> ScrewHelpers;

        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        {
            if (tasks == null)
                tasks = new Dictionary<string, TaskEx>();
            tasks.Clear();

            if (ScrewHelpers == null)
                ScrewHelpers = new Dictionary<string, ScrewHelper>();
            ScrewHelpers.Clear();

            if (PlcCommManger.Instance.PLCScrewAdrs == null)
                return;

            foreach (var item in PlcCommManger.Instance.PLCScrewAdrs)
            {
                //电批
                ScrewHelper screwHelper = new ScrewHelper(item.Name);
                ScrewHelpers.Add(item.Name, screwHelper);

                //监控
                TaskEx taskEx = new TaskEx();
                taskEx.Start(item.Name, () => ToDo(item));
                tasks.Add(item.Name, taskEx);
            }
            //开启一个获取PLC生产信息的线程
            TaskEx wip = new TaskEx();
            wip.Start("Wip", () => GetWip(PlcCommManger.Instance.WipAdr));
            tasks.Add("Wip", wip);
        }
        public void Stop()
        {
            foreach (var item in tasks)
            {
                item.Value?.Cancel();
            }
        }
        private void GetWip(WipAdr adr)
        {
            if (adr == null)
                return;

            var opWip = PLCFactory.Instance.Read("", 100);
        }
        private void ToDo(ScrewAdr adr)
        {
            //根据长度来读取PLC数据包括【视觉补偿，视觉坐标，图像坐标，视觉结果】
            //监控PLC地址【电批启动了】
            var opResult = PLCFactory.Instance.ReadBool(adr.AdrScrewStart);
            string barcode = "";
            string pid = "";
            int location = 1;
            bool isFinal = false;

            //开始接收电批数据
            if (opResult.IsSuccess && opResult.Content)
            {
                if (location == Appbus.Screw_Qty)
                    isFinal = true;

                LogHelper.Instance.Info($"【{adr.Name}】电批启动");

                var product = GetProduct(barcode, pid);

                TB_Screw screwData = new TB_Screw();
                screwData.Name = adr.Name;
                screwData.Pid = product.Pid;
                screwData.Barcode = barcode;
                screwData.Location = location + "";
                screwData.CCD_Result = "";
                screwData.ProductHole_X = 0;
                screwData.ProductHole_Y = 0;
                screwData.ScrewHole_X = 0;
                screwData.ScrewHole_Y = 0;
                screwData.Offset_X = 0;
                screwData.Offset_Y = 0;
                screwData.OffsetAngle = 0;
                screwData.Productoffset_X = 0;
                screwData.Productoffset_Y = 0;

                //监控地址关闭
                PLCFactory.Instance.Write(adr.AdrScrewStart, false);
                ScrewHelpers[adr.Name].A_Data = screwData;
                bool recSuccess = ScrewHelpers[adr.Name].Start();
                if (!recSuccess)
                {
                    PLCFactory.Instance.Write(adr.AdrScrewComplete, false);
                    return;
                }

                //收到数据给到PLC
                PLCFactory.Instance.Write(adr.AdrScrewComplete, true);

                if (!WaitIoResult(screwData, adr.AdrScrewIoResult))
                {
                    screwData.Accumulative_Result = (screwData.Result == "PASS" && screwData.m_Accumulative_Result == "OK") ? "OK" : "NG";

                    //整理数据
                    ScrewHelpers[adr.Name].Save();

                    product.EndTime = DateTime.Now;
                    DBHelper.Instance.Sql.Updateable(product).ExecuteCommand();

                    if (isFinal)
                    {
                        var _product = DBHelper.Instance.Sql.Queryable<TB_Product>()
                                            .Includes(x => x.ScrewDatas)
                                            .Where(x => x.Pid == pid && x.Barcode == product.Barcode)
                                            .First();

                        //本地文件保存
                        ExcelHelper.Save(_product);
                        //hive
                        HiveHelper.Instance.Send(_product);
                    }
                }

                //最终结果给PLC
                PLCFactory.Instance.Write(adr.AdrScrewFinalResult, screwData.Accumulative_Result == "OK" ? true : false);
            }
        }
        private bool WaitIoResult(TB_Screw screwData, string adrScrewIoResult)
        {
            //再次获取PLC的最终结果,等待3000毫秒的时间去监控
            bool isTimeOut = true;
            Stopwatch stopwatch = Stopwatch.StartNew();
            while (stopwatch.ElapsedMilliseconds > 3000 && isTimeOut)
            {
                var opIoResult = PLCFactory.Instance.ReadBool(adrScrewIoResult);
                if (opIoResult.IsSuccess)
                {
                    screwData.Result = opIoResult.Content ? "PASS" : "FAIL";
                    isTimeOut = false;
                }
            }
            if (isTimeOut)
                LogHelper.Instance.Alarm("", "获取PLC电批IO结果超时3秒");
            return isTimeOut;
        }
        private TB_Product GetProduct(string barcode, string pid)
        {
            lock (dbLocker)
            {
                var product = DBHelper.Instance.Sql.Queryable<TB_Product>()
                                                   .Where(p => p.Pid == pid && p.Barcode == barcode)
                                                   .First();
                if (product == null)
                {
                    product = new TB_Product();
                    product.Pid = pid;
                    product.Barcode = barcode;
                    product.StartTime = DateTime.Now;
                    DBHelper.Instance.Sql.Insertable(product).ExecuteCommand();
                }
                return product;
            }
        }

    }
}
